package com.admin.service.impl;

import com.admin.entity.SysPermission;
import com.admin.entity.SysRolePermission;
import com.admin.entity.SysUserRole;
import com.admin.exception.BusinessException;
import com.admin.exception.code.BaseResponseCode;
import com.admin.mapper.SysPermissionMapper;
import com.admin.mapper.SysRolePermissionMapper;
import com.admin.mapper.SysUserRoleMapper;
import com.admin.service.PermissionService;
import com.admin.service.RolePermissionService;
import com.admin.service.UserRoleService;
import com.admin.utils.AssertUtil;
import com.admin.utils.ConvertUtils;
import com.admin.web.request.PermissionAddReq;
import com.admin.web.response.PermissionNodeResp;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 权限管理
 */
@Service
@Slf4j
public class PermissionServiceImpl implements PermissionService {

    @Resource
    private UserRoleService userRoleService;

    @Resource
    private RolePermissionService rolePermissionService;

    @Resource
    private SysUserRoleMapper sysUserRoleMapper;

    @Resource
    private SysRolePermissionMapper sysRolePermissionMapper;

    @Resource
    private SysPermissionMapper sysPermissionMapper;

    @Override
    public SysPermission getById(String id) {
        return sysPermissionMapper.selectById(id);
    }

    @Override
    public void addPermission(PermissionAddReq permissionAddReq) {
        SysPermission sysPermission = ConvertUtils.convert(permissionAddReq, SysPermission.class);
        verifyFormPid(sysPermission);
        sysPermissionMapper.insert(sysPermission);
    }

    /**
     * 操作后的菜单类型是目录的时候 父级必须为目录
     * 操作后的菜单类型是菜单的时候，父类必须为目录类型
     * 操作后的菜单类型是按钮的时候 父类必须为菜单类型
     */
    @Override
    public void verifyFormPid(SysPermission sysPermission) {
        SysPermission parent;
        parent = sysPermissionMapper.selectById(sysPermission.getPid());
        switch (sysPermission.getType()) {
            case 1:
                if (parent != null) {
                    if (parent.getType() != 1) {
                        throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_CATALOG_ERROR);
                    }
                } else if (!"0".equals(sysPermission.getPid())) {
                    throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_CATALOG_ERROR);
                }
                break;
            case 2:
                if (parent == null || parent.getType() != 1) {
                    throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_MENU_ERROR);
                }
                if (StringUtils.isEmpty(sysPermission.getUrl())) {
                    throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_URL_NOT_NULL);
                }

                break;
            case 3:
                if (parent == null || parent.getType() != 2) {
                    throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_BTN_ERROR);
                }
                if (StringUtils.isEmpty(sysPermission.getPerms())) {
                    throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_URL_PERMS_NULL);
                }
                if (StringUtils.isEmpty(sysPermission.getUrl())) {
                    throw new BusinessException(BaseResponseCode.OPERATION_MENU_PERMISSION_URL_NOT_NULL);
                }
                break;
            default:
        }
    }

/**
 * 通过用户ID查询权限
 *
 * @param userId userId
 * @return
 */
@Override
public List<SysPermission> getPermission(String userId) {
    List<String> roleIds = userRoleService.getRoleIdsByUserId(userId);
    if (CollectionUtils.isEmpty(roleIds)) {
        return null;
    }
    List<String> permissionIds = rolePermissionService.getPermissionIds(roleIds);
    if (CollectionUtils.isEmpty(permissionIds)) {
        return null;
    }
    LambdaQueryWrapper<SysPermission> queryWrapper = Wrappers.<SysPermission>lambdaQuery().in(SysPermission::getId, permissionIds).eq(SysPermission::getStatus, 1).orderByAsc(SysPermission::getOrderNum);
    return sysPermissionMapper.selectList(queryWrapper);
}

/**
 * 删除菜单权限
 * 判断是否 有角色关联
 * 判断是否有子集
 */
@Transactional(rollbackFor = Exception.class)
@Override
public void deleted(String permissionId) {
    SysPermission sysPermission = sysPermissionMapper.selectById(permissionId);
    if (null == sysPermission) {
        throw new BusinessException(BaseResponseCode.DATA_ERROR);
    }
    //获取下一级
    List<SysPermission> childs = sysPermissionMapper.selectList(Wrappers.<SysPermission>lambdaQuery().eq(SysPermission::getPid, permissionId));
    if (!CollectionUtils.isEmpty(childs)) {
        throw new BusinessException(BaseResponseCode.ROLE_PERMISSION_RELATION);
    }
    sysPermissionMapper.deleteById(permissionId);
    //删除和角色关联
    sysRolePermissionMapper.delete(Wrappers.<SysRolePermission>lambdaQuery().eq(SysRolePermission::getPermissionId, permissionId));

}

@Override
public void updatePermission(SysPermission vo) {
    AssertUtil.isStringNotBlank(vo.getId(), "id不能为空");
    SysPermission sysPermission = sysPermissionMapper.selectById(vo.getId());
    if (null == sysPermission) {
        throw new BusinessException(BaseResponseCode.DATA_ERROR);
    }
    // 只有类型变更或者所属菜单变更
    if (sysPermission.getType().equals(vo.getType()) || !sysPermission.getPid().equals(vo.getPid())) {
        verifyFormPid(vo);
    }
    sysPermissionMapper.updateById(vo);
}

/**
 * 获取所有菜单权限
 */
@Override
public List<SysPermission> selectAll(Integer status) {
    List<SysPermission> result = sysPermissionMapper.selectList(Wrappers.<SysPermission>lambdaQuery().eq(status != null, SysPermission::getStatus, status).orderByAsc(SysPermission::getOrderNum));
    if (!CollectionUtils.isEmpty(result)) {
        for (SysPermission sysPermission : result) {
            SysPermission parent = sysPermissionMapper.selectById(sysPermission.getPid());
            if (parent != null) {
                sysPermission.setPidName(parent.getName());
            }
        }
    }
    return result;
}

/**
 * 获取权限标识
 */
@Override
public List<String> getPermissionsByUserId(String userId) {

    List<SysPermission> list = getPermission(userId);
    Set<String> permissions = new HashSet<>();
    if (CollectionUtils.isEmpty(list)) {
        return null;
    }
    for (SysPermission sysPermission : list) {
        if (!StringUtils.isEmpty(sysPermission.getPerms())) {
            permissions.add(sysPermission.getPerms());
        }

    }
    return new ArrayList<String>(permissions);
}

/**
 * 以树型的形式把用户拥有的菜单权限返回给客户端
 */
@Override
public List<PermissionNodeResp> permissionTreeList(String userId) {
    List<SysPermission> list = getPermission(userId);
    return getTree(list, true);
}

/**
 * 递归获取菜单树
 */
private List<PermissionNodeResp> getTree(List<SysPermission> all, boolean type) {

    List<PermissionNodeResp> list = new ArrayList<>();
    if (CollectionUtils.isEmpty(all)) {
        return list;
    }
    for (SysPermission sysPermission : all) {
        if ("0".equals(sysPermission.getPid())) {
            PermissionNodeResp permissionRespNode = new PermissionNodeResp();
            BeanUtils.copyProperties(sysPermission, permissionRespNode);
            permissionRespNode.setTitle(sysPermission.getName());

            if (type) {
                permissionRespNode.setChildren(getChildExcBtn(sysPermission.getId(), all));
            } else {
                permissionRespNode.setChildren(getChildAll(sysPermission.getId(), all));
            }
            list.add(permissionRespNode);
        }
    }
    return list;
}

/**
 * 递归遍历所有
 */
private List<PermissionNodeResp> getChildAll(String id, List<SysPermission> all) {

    List<PermissionNodeResp> list = new ArrayList<>();
    for (SysPermission sysPermission : all) {
        if (sysPermission.getPid().equals(id)) {
            PermissionNodeResp permissionRespNode = new PermissionNodeResp();
            BeanUtils.copyProperties(sysPermission, permissionRespNode);
            permissionRespNode.setTitle(sysPermission.getName());
            permissionRespNode.setChildren(getChildAll(sysPermission.getId(), all));
            list.add(permissionRespNode);
        }
    }
    return list;
}

/**
 * 只递归获取目录和菜单
 */
private List<PermissionNodeResp> getChildExcBtn(String id, List<SysPermission> all) {

    List<PermissionNodeResp> list = new ArrayList<>();
    for (SysPermission sysPermission : all) {
        if (sysPermission.getPid().equals(id) && sysPermission.getType() != 3) {
            PermissionNodeResp permissionRespNode = new PermissionNodeResp();
            BeanUtils.copyProperties(sysPermission, permissionRespNode);
            permissionRespNode.setTitle(sysPermission.getName());
            permissionRespNode.setChildren(getChildExcBtn(sysPermission.getId(), all));
            list.add(permissionRespNode);
        }
    }
    return list;
}

/**
 * 获取所有菜单权限按钮
 */
@Override
public List<PermissionNodeResp> selectAllByTree(Integer status) {

    List<SysPermission> list = selectAll(status);
    return getTree(list, false);
}

/**
 * 获取所有的目录菜单树排除按钮
 * 因为不管是新增或者修改
 * 选择所属菜单目录的时候
 * 都不可能选择到按钮
 * 而且编辑的时候 所属目录不能
 * 选择自己和它的子类
 */
@Override
public List<PermissionNodeResp> selectAllMenuByTree(String permissionId) {

    List<SysPermission> list = selectAll(1);
    if (!CollectionUtils.isEmpty(list) && !StringUtils.isEmpty(permissionId)) {
        for (SysPermission sysPermission : list) {
            if (sysPermission.getId().equals(permissionId)) {
                list.remove(sysPermission);
                break;
            }
        }
    }
    List<PermissionNodeResp> result = new ArrayList<>();
    //新增顶级目录是为了方便添加一级目录
    PermissionNodeResp respNode = new PermissionNodeResp();
    respNode.setId("0");
    respNode.setTitle("默认顶级菜单");
    respNode.setSpread(true);
    respNode.setChildren(getTree(list, true));
    result.add(respNode);
    return result;
}

@Override
public List<String> getUserIdsById(String id) {
    //根据权限id，获取所有角色id
    //根据权限id，获取所有角色id
    List<String> roleIds = rolePermissionService.getRoleIds(id);
    if (!CollectionUtils.isEmpty(roleIds)) {
        List<SysUserRole> sysUserRoles = sysUserRoleMapper.selectList(Wrappers.<SysUserRole>lambdaQuery().select(SysUserRole::getUserId).in(SysUserRole::getRoleId, roleIds));
        //根据角色id， 获取关联用户
        return sysUserRoles.stream().map(SysUserRole::getUserId).collect(Collectors.toList());
    }
    return null;
}


}
